<?php

namespace common\models;

use common\helpers\Helper;
use common\Service\RedisService;
use Yii;
use common\models\Common;


/**
 * This is the model class for table "{{%star}}".
 *
 * @property string $id
 * @property string $name
 * @property string $nick_name
 * @property string $header
 * @property string $desc
 * @property integer $age
 * @property string $birthday
 * @property integer $star_sign
 * @property string $birth_place
 * @property integer $height
 * @property integer $weight
 * @property string $size
 * @property string $job
 * @property string $interest
 * @property string $blood_type
 * @property string $animal
 * @property integer $status
 */
class Star extends Common
{
    public static $fields = ['id','name','nick_name','header','desc','age','birthday','star_sign','birth_place','height','weight','size','job','interest','blood_type','animal','status','tags','view','country'];
    /**
     * @inheritdoc
     */
    public static function tableName()
    {
        return '{{%star}}';
    }

    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['desc'], 'string'],
            [['age', 'birthday', 'star_sign', 'height', 'weight', 'status'], 'integer'],
            [['name', 'birth_place'], 'string', 'max' => 80],
            [['nick_name', 'interest','country', 'alias'], 'string', 'max' => 50],
            [['header','job'], 'string', 'max' => 100],
            [['tags'], 'string', 'max' => 120],
            [['size'], 'string', 'max' => 50],
            [['blood_type', 'animal'], 'string', 'max' => 5],
            [['score'], 'number'],
            [['name'], 'unique'],
        ];
    }

    /**
     * @inheritdoc
     */
    public function attributeLabels()
    {
        return [
            'id' => 'ID',
            'name' => '名字',
            'nick_name' => '昵称',
            'header' => '头像',
            'desc' => '描述',
            'age' => '年龄',
            'birthday' => '生日',
            'star_sign' => '星座',
            'birth_place' => '出生地',
            'height' => '身高',
            'weight' => '体重',
            'size' => '三围',
            'job' => '职业',
            'interest' => '兴趣',
            'blood_type' => '血型',
            'animal' => '属相',
            'status' => 'Status',
            'tags' => '标签',
            'view' => '浏览量'
        ];
    }

    public static function getStarInfoById($starId = 0,$fields = [],$ranking = true){
        $starInfo = [];
        $starId = intval($starId);
        if($starId == 0) return $starInfo;

        empty($fields) && $fields = static::$fields;

        $starInfo = RedisService::getHash("star:".$starId,$fields);
        if(empty($starInfo)){
            $starInfo = Star::find()
                ->where(['id' => $starId])
                ->select($fields)
                ->asArray()
                ->one();
        }

        if($starInfo){
            $starInfo = static::formatStarInfo($starInfo);
            $ranking && $starInfo['ranking'] = static::getRanking($starId);
        }

        return $starInfo;
    }

    /**
     * TagModel->parseTags 后的信息
     * 逻辑说明 多个标签的时候 取明星数据通过“全部交集”的方式获取
     * @param array $tags
     * @param int $currentPage
     * @param int $perPage
     * @param array $fields
     * @return array|mixed
     */
    public static function getStarByTags($tags = [],$currentPage = 1, $perPage = 10,$fields = []){
        $tagCount = count($tags);
        //没有查询条件 直接读取总的明星列表
        if($tagCount === 0) return static::getMaxViewStar($currentPage,$perPage,$fields);

        $redisKey = '';
        //只有一个标签，直接读取该标签的数据即可
        if(count($tags) === 1){
            $redisKey = 'tagZset:'.trim($tags[0]['alias']);
        }else{
            $alias = array_column($tags,'alias');
            $alias = array_map(function($value){
                return 'tagZset:'.trim($value);
            },$alias);
            $redisKey = RedisService::zInterStore($alias);
        }

        $rs = RedisService::pageData($redisKey,$currentPage,$perPage,'zset');
        $rs['data'] = static::formatStars($rs['data'],$fields);
        return $rs;

    }

    /**
     * @desc 获取浏览量最高的明星数据
     * @param int $currentPage
     * @param int $perPage
     * @param array $fields
     * @return array
     */
    public static function getMaxViewStar($currentPage = 1, $perPage = 10,$fields = []){
        $rs = RedisService::pageData('starZset',$currentPage,$perPage,'zset');

        $rs['data'] = static::formatStars($rs['data'],$fields);

        return $rs;
    }

    /**
     * @desc 格式化明星列表
     * @param array $starIds
     * @param array $fields
     * @return array
     */
    public static function formatStars($starIds = [],$fields = []){
        $rs = [];

        if($starIds){
            empty($fields) && $fields = static::$fields;

            foreach ($starIds as $id){
                $starInfo = static::getStarInfoById($id,$fields);
                $starInfo && $rs[] = $starInfo;
            }
        }

        return $rs;
    }

    /**
     * @desc 格式化明星列表
     * @param array $starInfo
     * @return array
     */
    public static function formatStarInfo($starInfo = []){
        if(empty($starInfo)) return [];

        $fields = array_keys($starInfo);
        if(in_array('header',$fields)){
            $starInfo['header'] = empty($starInfo['header']) ? Helper::parseImg("/star/{$starInfo['id']}/header.jpg") : Helper::parseImg($starInfo['header']);
        }

        return $starInfo;
    }

    /**
     * @desc 获取明星总排名
     * @param int $starId
     * @return int
     */
    public static function getRanking($starId = 0){
        return (int)Yii::$app->get('redis')->zrevrank('starZset',$starId) + 1;
    }

    /**
     * @desc 更新明星访问量同时记录明星每天每月的访问量
     * @param int $starId
     */
    public static function incrView($starId = 0){
        $redis = Yii::$app->get('redis');
        $starId = intval($starId);
        if($starId == 0) return;

        $increment = rand(1,3);
        $redis->hincrby('star:'.$starId,'view',$increment);//明星hash
        $redis->zincrby('starZset',$increment,$starId); //明星总榜

        //为各种明星榜单做基础数据 记录每个明星每天的访问量
        $starDayView = 'starDayView:'.date('Ymd',time());
        //记录每个明星每月的访问量
        $starMonthView = 'starMonthView:'.date('Ym',time());
        /*
         * 例如：
         * starDayView:20171012 = [starA=>3,starB=>4,c=>5]
         * starDayView:20171013 = [starA=>5,starB=>4,c=>0]
         * 直接取并集 score默认求和 然后和各类型的榜单的明星ID取交集即可 明星的score默认为0
         * 交集结果缓存到每天晚上的12点过期 即可实现榜单每天自动更新
         *
         * 月榜：直接从starMonthView取值即可
         */
        $redis->zincrby($starDayView,$increment,$starId);
        $redis->zincrby($starMonthView,$increment,$starId);
    }

    /**
     * @desc 更新明星ID获取明星信息
     * @param $starIds 字符串的时候ID用逗号分开
     * @param array $fields
     * @return array
     */
    public static function getStarsByIds($starIds,$fields = []){
        if(is_string($starIds)){
            $starIds = explode(',',$starIds);
        }

        return static::formatStars($starIds,$fields);
    }

    /**
     * @desc 推荐女星
     * @param int $limit
     * @param array $fields
     * @return array
     */
    public static function recommendStars($limit = 4,$fields = []){
        $redis = Yii::$app->get('redis');

        if((int)$redis->exists('recommendStarSet') == 0){
            //获取有写真的明星，放入一个set，然后随机取，作为推荐女星
            $starIds = $redis->keys('tagPortraySet:*');
            foreach ($starIds as $starId){
                $starId = explode(':',$starId);
                isset($starId[1]) && intval($starId[1]) > 0 && $redis->sadd('recommendStarSet',intval($starId[1]));
            }
            $redis->expire('recommendStarSet',24 * 60 * 60); //每天更新
        }

        $starIds = $redis->srandmember('recommendStarSet',$limit);
        return static::formatStars($starIds,$fields);
    }


    public static function randomStars($limit = 5,$fields = [],$outIds = []){
        $redis = Yii::$app->get('redis');

        $minId = 16667;
        $maxId = (int)$redis->get('maxStarId');
        $maxId == 0 && $maxId = Star::find()->max('id');

        $starIds = [];
        $i = 0;

        $out = empty($outIds) ? false : true;
        while ($i < $limit){
            $starId = rand($minId,$maxId);
            if(!in_array($starId,$starIds)){
                if($out){
                    if(!in_array($starId,$outIds)){
                        $starIds[] = $starId;
                        $i++;
                    }
                }else{
                    $starIds[] = $starId;
                    $i++;
                }
            }

        }

        return Star::formatStars($starIds,$fields);
    }


    /**
     * @desc 根据ID排序的明星数据 默认倒序
     * @param int $currentPage
     * @param int $perPage
     * @param array $fields
     * @param int $sort
     * @return array
     */
    public static function latestStars($currentPage = 1, $perPage = 10,$fields = [],$sort = SORT_DESC){
        return static::randomStars(6);
    }
}
